package org.abratuhi.kvngroupware.network;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Properties;

import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.ResourceIterator;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.CollectionManagementService;
import org.xmldb.api.modules.XMLResource;
import org.xmldb.api.modules.XPathQueryService;

public abstract class AbstractDbMessageProceeder {
	
	Properties props;
	
	String root_collection = "xmldb:exist://localhost:8080/exist/xmlrpc/db";
	String root_user = "admin";
	String root_password = "rondalfa";
	
	String kvn_collection = "xmldb:exist://localhost:8080/exist/xmlrpc/db/kvn";
	String kvn_user = "kvnuser";
	String kvn_password = "kvn";
	
	public AbstractDbMessageProceeder(Properties properties){
		props = properties;
		root_collection = props.getProperty("exist.uri");
		root_user = props.getProperty("exist.user");
		root_password = props.getProperty("exist.password");
		kvn_collection = props.getProperty("exist.kvn.uri");
		kvn_user = props.getProperty("exist.kvn.user");
		kvn_password = props.getProperty("exist.kvn.password");
	}
	
	@SuppressWarnings("unchecked")
	public ResourceSet executeQuery(String collection, String user, String password, String query){
		try {
			Class cl = Class.forName("org.exist.xmldb.DatabaseImpl");
			DatabaseManager.registerDatabase((Database)cl.newInstance());

			Collection dbCollection = DatabaseManager.getCollection(collection, user, password);
			
			if(dbCollection == null && collection.equals(kvn_collection)){
				initKVNDbContext();
				dbCollection = DatabaseManager.getCollection(collection, user, password);
			}
			
			XPathQueryService xPathService = (XPathQueryService) dbCollection.getService("XPathQueryService", "1.0");  
			xPathService.setProperty("indent", "yes");

			ResourceSet result = xPathService.query(query);
			return result;
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (XMLDBException e) {
			e.printStackTrace();
		}
		return null;
	}
	
	public ResourceSet executeQuery(String query){
		return executeQuery(kvn_collection, kvn_user, kvn_password, query);
	}
	
	public void initKVNDbContext(){
		addCollectionAndFiles(root_collection, "kvn", new String[]{"users.xml", "teams.xml"}, new String[]{"<users/>", "<teams/>"},  kvn_user, kvn_password);
	}
	
	@SuppressWarnings("unchecked")
	public void addCollectionAndFiles(String rootCollection, String newCollection, String[] files, String user, String password){
		try {
			Class cl = Class.forName("org.exist.xmldb.DatabaseImpl");
			DatabaseManager.registerDatabase((Database)cl.newInstance());

			Collection rootDbCollection = DatabaseManager.getCollection(rootCollection, user, password);
			
			CollectionManagementService mgtService = (CollectionManagementService) rootDbCollection.getService("CollectionManagementService", "1.0");
			
			Collection newDbCollection = mgtService.createCollection(newCollection);
			
			for(int i=0; i<files.length; i++){
				newDbCollection.storeResource(newDbCollection.createResource(files[i], "XMLResource"));
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (XMLDBException e) {
			e.printStackTrace();
		}
	}
	
	@SuppressWarnings("unchecked")
	public void addCollectionAndFiles(String rootCollection, String newCollection, String[] files, String[] contents, String user, String password){
		try {
			Class cl = Class.forName("org.exist.xmldb.DatabaseImpl");
			DatabaseManager.registerDatabase((Database)cl.newInstance());

			Collection rootDbCollection = DatabaseManager.getCollection(rootCollection, user, password);
			
			CollectionManagementService mgtService = (CollectionManagementService) rootDbCollection.getService("CollectionManagementService", "1.0");
			
			Collection newDbCollection = mgtService.createCollection(newCollection);
			
			for(int i=0; i<files.length; i++){
				XMLResource newDbResource = (XMLResource) newDbCollection.createResource(files[i], "XMLResource");
				newDbResource.setContent(contents[i]);
				newDbCollection.storeResource(newDbResource);
			}
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (XMLDBException e) {
			e.printStackTrace();
		}
	}
	
	public Element convertXMLResourceToElement(XMLResource xmlresource){
		Element element = null;
		SAXBuilder saxbuilder = new SAXBuilder();
		try {
			element = (Element) saxbuilder.build(new StringReader((String) xmlresource.getContent())).getRootElement().detach();
		} catch (JDOMException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (XMLDBException e) {
			e.printStackTrace();
		}
		return element;
	}
	public Element[] convertResourceSetToElements(ResourceSet resourceset){
		ArrayList<Element> elements = new ArrayList<Element>();
		try {
			ResourceIterator iterator = resourceset.getIterator();
			while(iterator.hasMoreResources()){
				XMLResource resource = (XMLResource) iterator.nextResource();
				Element element = convertXMLResourceToElement(resource);
				if(element != null) elements.add(element);
			}
		} catch (XMLDBException e) {
			e.printStackTrace();
		}
		return elements.toArray(new Element[elements.size()]);
	}
	
	public String convertElementToString(Element element){
		XMLOutputter xmlout = new XMLOutputter();
		StringWriter sw = new StringWriter();
		try {
			xmlout.output(element, sw);
			return sw.toString();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

}
